package com.surekam.core.rsa;

import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class RSA {
	// private static RSAPublicKey publicKey;
	private static final String DEFAULT_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHn/hfvTLRXViBXTmBhNYEIJeG"
			+ "\r" + "GGDkmrYBxCRelriLEYEcrwWrzp0au9nEISpjMlXeEW4+T82bCM22+JUXZpIga5qd" + "\r"
			+ "BrPkjU08Ktf5n7Nsd7n9ZeI0YoAKCub3ulVExcxGeS3RVxFai9ozERlavpoTOdUz" + "\r" + "EH6YWHP4reFfpMpLzwIDAQAB"
			+ "\r";

	/**
	 * 从字符串中加载公钥
	 * 
	 * @param publicKeyStr
	 *            公钥数据字符串
	 * @throws Exception
	 *             加载公钥时产生的异常
	 */
	public RSAPublicKey loadPublicKey(String publicKeyStr) throws Exception {
		try {
			// BASE64Decoder base64Decoder = new BASE64Decoder();
			// byte[] buffer = base64Decoder.decodeBuffer(publicKeyStr);
			byte[] buffer = null;
			if (publicKeyStr != null)
				buffer = Base64.decodeBase64(publicKeyStr);
			else
				buffer = Base64.decodeBase64(DEFAULT_PUBLIC_KEY);
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
			RSAPublicKey publicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec);

			return publicKey;
		} catch (NoSuchAlgorithmException e) {
			throw new Exception("无此算法");
		} catch (InvalidKeySpecException e) {
			throw new Exception("公钥非法");
		} catch (NullPointerException e) {
			throw new Exception("公钥数据为空");
		}
	}

	/**
	 * 加密过程
	 * 
	 * @param publicKey
	 *            公钥
	 * @param plainTextData
	 *            明文数据
	 * @return
	 * @throws Exception
	 *             加密过程中的异常信息
	 */
	public byte[] encrypt(RSAPublicKey publicKey, byte[] plainTextData) throws Exception {
		if (publicKey == null) {
			throw new Exception("加密公钥为空, 请设置");
		}
		Cipher cipher = null;
		try {
			cipher = Cipher.getInstance("RSA", new BouncyCastleProvider());

			cipher.init(Cipher.ENCRYPT_MODE, publicKey);

			byte[] output = new byte[] {};
			
			for (int i = 0; i < plainTextData.length; i += 117) {
				byte[] subarray = ArrayUtils.subarray(plainTextData, i, i + 117);
				byte[] doFinal = cipher.doFinal(subarray);
				output = ArrayUtils.addAll(output, doFinal);
			}
			System.out.println(output.length);
			// byte[] output = cipher.doFinal(plainTextData);
			return output;
		} catch (NoSuchAlgorithmException e) {
			throw new Exception("无此加密算法");
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
			return null;
		} catch (InvalidKeyException e) {
			throw new Exception("加密公钥非法,请检查");
		} catch (IllegalBlockSizeException e) {
			throw new Exception("明文长度非法");
		} catch (BadPaddingException e) {
			throw new Exception("明文数据已损坏");
		}
	}

	public static void main(String[] args) throws Exception {
		String keyStr = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHn/hfvTLRXViBXTmBhNYEIJeG" + "\r"
				+ "GGDkmrYBxCRelriLEYEcrwWrzp0au9nEISpjMlXeEW4+T82bCM22+JUXZpIga5qd" + "\r"
				+ "BrPkjU08Ktf5n7Nsd7n9ZeI0YoAKCub3ulVExcxGeS3RVxFai9ozERlavpoTOdUz" + "\r"
				+ "EH6YWHP4reFfpMpLzwIDAQAB" + "\r";

		RSA r = new RSA();
		RSAPublicKey publicKey = r.loadPublicKey(null);
		System.out.println(publicKey.toString());
		String text = "{'username':'hn12396','token':'5eeb3eb0c7e6ed9d69f1b4fd838a579e','functionName':'preLogin','uuid':'C80AA99AEC09','request':{'ovVersion':'Windows','deviceType':'pc','clientVersion':'1.0'}}";
		byte[] compress = GZIP.compress(text);
		byte[] encrypted = r.encrypt(publicKey, compress);
//		byte[] encrypt = r.encrypt(publicKey, text.getBytes("UTF-8"));
		System.out.println(encrypted);
		
	}
}
